#include "../inc/ff_utils_window.h"

namespace feifei
{
	static const int PrintBufferSize = 1024;
	static char PrintBuffer[PrintBufferSize];
	static time_t t;
	static struct tm stm;
	static std::string getCurrentTime()
	{
		memset(PrintBuffer, 0, PrintBufferSize);
		t = time(0);
		localtime_s(&stm, &t);
		strftime(PrintBuffer, PrintBufferSize, "[%H:%M:%S]", &stm);
		return std::string(PrintBuffer);
	}
	void wPrintInfo(const char* format, ...)
	{
#if defined(DEBUG) || defined(_DEBUG) 
		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
		vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
		va_end(args);
		std::string _string(PrintBuffer);
		OutputDebugString(str_to_wstr(_string).c_str());
		OutputDebugString(L"\n");
#endif
	}
	void wPrintInfo(std::string msg, ...)
	{
#if defined(DEBUG) || defined(_DEBUG) 
		OutputDebugString(str_to_wstr(msg).c_str());
		OutputDebugString(L"\n");
#endif
	}

	void wPrintLog(const char* format, ...)
	{
#if defined(DEBUG) || defined(_DEBUG) 
		OutputDebugString(L"[  LOG  ]");
		OutputDebugString(str_to_wstr(getCurrentTime()).c_str());

		memset(PrintBuffer, 0, PrintBufferSize);
		va_list args;
		va_start(args, format);
		vsprintf_s(PrintBuffer, PrintBufferSize, format, args);
		va_end(args);
		std::string _string(PrintBuffer);
		OutputDebugString(str_to_wstr(_string).c_str());
		OutputDebugString(L"\n");
#endif
	}
	void wPrintLog(std::string msg, ...)
	{
#if defined(DEBUG) || defined(_DEBUG) 
		OutputDebugString(L"[  LOG  ]");
		OutputDebugString(str_to_wstr(getCurrentTime()).c_str());
		OutputDebugString(str_to_wstr(msg).c_str());
		OutputDebugString(L"\n");
#endif
	}




	WinAppBase* WinAppBase::gWinApp = nullptr;
	LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		return WinAppBase::GetApp()->MsgProc(hwnd, msg, wParam, lParam);
	}

	WinAppBase::WinAppBase(HINSTANCE hInstance)
	{
		mhAppInst = hInstance;
		assert(gWinApp == nullptr);
		gWinApp = this;
	}
	WinAppBase* WinAppBase::GetApp()
	{
		return gWinApp;
	}
	bool WinAppBase::Init(std::wstring caption, int width, int height)
	{
		mMainWndCaption = caption;
		mClientWidth = width;
		mClientHeight = height;

		WNDCLASS wc;
		wc.style = CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc = MainWndProc;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hInstance = mhAppInst;
		wc.hIcon = LoadIcon(0, IDI_APPLICATION);
		wc.hCursor = LoadCursor(0, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
		wc.lpszMenuName = 0;
		wc.lpszClassName = L"MainWnd";

		if (!RegisterClass(&wc))
		{
			MessageBox(0, L"RegisterClass Failed.", 0, 0);
			return false;
		}

		// Compute window rectangle dimensions based on requested client area dimensions.
		RECT R = { 0, 0, mClientWidth, mClientHeight };
		AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
		int _width = R.right - R.left;
		int _height = R.bottom - R.top;

		mhMainWnd = CreateWindow(L"MainWnd", mMainWndCaption.c_str(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, _width, _height, 0, 0, mhAppInst, 0);
		if (!mhMainWnd)
		{
			MessageBox(0, L"CreateWindow Failed.", 0, 0);
			return false;
		}

		ShowWindow(mhMainWnd, SW_SHOW);
		UpdateWindow(mhMainWnd);

		return true;
	}
	int WinAppBase::Run()
	{
		MSG msg = { 0 };

		while (msg.message != WM_QUIT)
		{
			// If there are Window messages then process them.
			if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			// Otherwise, do animation/game stuff.
			else
			{
				if(mRunFuncPtr != nullptr)
					(*mRunFuncPtr)();
				//Sleep(100);
			}
		}

		return (int)msg.wParam;
	}
	LRESULT WinAppBase::MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		switch (msg)
		{
		case WM_SIZE:
			mClientWidth = LOWORD(lParam);
			mClientHeight = HIWORD(lParam);
			return 0;

		case WM_LBUTTONDOWN:
		case WM_MBUTTONDOWN:
		case WM_RBUTTONDOWN:
			OnMouseDown(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
			return 0;
		case WM_LBUTTONUP:
		case WM_MBUTTONUP:
		case WM_RBUTTONUP:
			OnMouseUp(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
			return 0;
		case WM_MOUSEMOVE:
			OnMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
			return 0;
		case WM_KEYUP:
			if (wParam == VK_ESCAPE)
			{
				PostQuitMessage(0);
			}
			return 0;

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
		}

		return DefWindowProc(hwnd, msg, wParam, lParam);
	}


	// this is the main message handler for the program
	LRESULT CALLBACK WindowBase::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
	{
		/*WindowsApplication* pThis;
		if (message == WM_NCCREATE)
		{
			pThis = static_cast<WindowsApplication*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);

			SetLastError(0);
			if (!SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis)))
			{
				if (GetLastError() != 0)
					return FALSE;
			}
		}
		else
		{
			pThis = reinterpret_cast<WindowsApplication*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
		}

		// sort through and find what code to run for the message given
		switch (message)
		{
		case WM_PAINT:
		{
			g_pApp->OnDraw();
		}
		break;
		case WM_KEYUP:
		{
			switch (wParam)
			{
			case VK_LEFT:
				g_pInputManager->LeftArrowKeyUp();
				break;
			case VK_RIGHT:
				g_pInputManager->RightArrowKeyUp();
				break;
			case VK_UP:
				g_pInputManager->UpArrowKeyUp();
				break;
			case VK_DOWN:
				g_pInputManager->DownArrowKeyUp();
				break;
			default:
				break;
			}
		}
		break;
		case WM_KEYDOWN:
		{
			switch (wParam)
			{
			case VK_LEFT:
				g_pInputManager->LeftArrowKeyDown();
				break;
			case VK_RIGHT:
				g_pInputManager->RightArrowKeyDown();
				break;
			case VK_UP:
				g_pInputManager->UpArrowKeyDown();
				break;
			case VK_DOWN:
				g_pInputManager->DownArrowKeyDown();
				break;
			default:
				break;
			}
		}
		break;

		// this message is read when the window is closed
		case WM_DESTROY:
		{
			// close the application entirely
			PostQuitMessage(0);
			m_bQuit = true;
		}
		}*/

		// Handle any messages the switch statement didn't
		return DefWindowProc(hWnd, message, wParam, lParam);
	}

	void WindowBase::CreateMainWindow()
	{
		// get the HINSTANCE of the Console Program
		HINSTANCE hInstance = GetModuleHandle(NULL);

		// this struct holds information for the window class
		WNDCLASSEX wc;

		// clear out the window class for use
		ZeroMemory(&wc, sizeof(WNDCLASSEX));

		// fill in the struct with the needed information
		wc.cbSize = sizeof(WNDCLASSEX);
		wc.style = CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc = WindowProc;
		wc.hInstance = hInstance;
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
		wc.lpszClassName = _T("GameEngineFromScratch");

		// register the window class
		RegisterClassEx(&wc);

		// create the window and use the result as the handle
		m_hWnd = CreateWindowEx(0,
			_T("GameEngineFromScratch"),      // name of the window class
			m_winTitle,        // title of the window
			WS_OVERLAPPEDWINDOW,              // window style
			CW_USEDEFAULT,                    // x-position of the window
			CW_USEDEFAULT,                    // y-position of the window
			m_width,							// width of the window
			m_height,							// height of the window
			NULL,                             // we have no parent window, NULL
			NULL,                             // we aren't using menus, NULL
			hInstance,                        // application handle
			this);                            // pass pointer to current object

	// display the window on the screen
		ShowWindow(m_hWnd, SW_SHOW);

	}



} // end namespace feifei
